﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Microsoft.Win32;

using LevelEditor.Model.Entity;
using LevelEditor.View.Controls.Adorners;
using LevelEditor.View.UserControls;
using LevelEditor.Controllers;
using LevelEditor.Model.IO;
using LevelEditor.Model.Services;

namespace LevelEditor.View.Windows
{
    /// <summary>
    /// Logique d'interaction pour MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private List<GameSprite> gameSprites = null;
        private Level level;

        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += MainWindow_Loaded;
            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
            
            gameElementsPanel.SpriteBrushSelected += new EventHandler(OnGameElementPanelSpriteBrushSelected);

            scenePanel.SpriteAdded += new EventHandler(scenePanel_SpriteAdded);
            scenePanel.SpriteSelected += new EventHandler(scenePanel_SpriteSelected);
            scenePanel.SpriteDeselected += new EventHandler(scenePanel_SpriteDeselected);
            scenePanel.SpriteDeleted += new EventHandler(scenePanel_SpriteDeleted);
            scenePanel.MouseMove += new MouseEventHandler(scenePanel_MouseMove);

            layersPanel.SpriteSelected += new EventHandler(layersPanel_SpriteSelected);
            layersPanel.SceneSelected += new EventHandler(layersPanel_SceneSelected);
            layersPanel.SpritesZIndexChanged += new EventHandler(layersPanel_SpritesZIndexChanged);
            layersPanel.SpriteDeleted += new EventHandler(layersPanel_SpriteDeleted);

            navigatorPanel.ZoomValueChanged += new EventHandler(navigatorPanel_ZoomValueChanged);
        }

        protected void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            IDsService.Init();

            InitGameElements();
            level = CreateNewLevel();
            PrepareLevel();
        }

        private void InitGameElements()
        {
            gameElementsPanel.GameSprites = GameSpritesIO.LoadGameSprites();
        }

        private Level CreateNewLevel()
        {
            Level newlevel = new Level();
            newlevel.IsNew = true;
            newlevel.Name = "LevelTest";
            newlevel.Number = 0;

            Scene scene = new Scene();
            scene.BackgroundColor = Colors.White;
            scene.GridSquareSize = 20;
            scene.Width = 960;
            scene.Height = 640;

            scene.Layers = new List<Layer>();

            scene.Layers.Add(new Layer { Name = "Foreground", Icon = "/Assets/UI/ico_layers.png", IsItemLocked = false, IsItemVisible = true });
            scene.Layers.Add(new Layer { Name = "Middle Foreground", Icon = "/Assets/UI/ico_layers.png", IsItemLocked = false, IsItemVisible = true });
            scene.Layers.Add(new Layer { Name = "Playground", Icon = "/Assets/UI/ico_layers.png", IsItemLocked = false, IsItemVisible = true });
            scene.Layers.Add(new Layer { Name = "Middle Background", Icon = "/Assets/UI/ico_layers.png", IsItemLocked = false, IsItemVisible = true });
            scene.Layers.Add(new Layer { Name = "Background", Icon = "/Assets/UI/ico_layers.png", IsItemLocked = true, IsItemVisible = true });

            newlevel.Scene = scene;

            return newlevel;
        }

        private void PrepareLevel()
        {
            if (level == null) return;

            navigatorPanel.ZoomValue = 100; //This fix a problem when loading scene
            scenePanel.Zoom(100);

            layersPanel.Scene = level.Scene;
            scenePanel.Scene = level.Scene;
            propertiesPanel.Scene = level.Scene;
            propertiesPanel.ShowSceneProperties();

            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }


        //Event Handler

        protected void scenePanel_SpriteAdded(object sender, EventArgs e)
        {
            layersPanel.AddSprite((GameSprite)sender);
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }

        protected void scenePanel_SpriteSelected(object sender, EventArgs e)
        {
            layersPanel.SelectSprite((GameSprite)sender);
            propertiesPanel.SelectedSprite = (GameSprite)sender;
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }
        protected void scenePanel_SpriteDeselected(object sender, EventArgs e)
        {
            layersPanel.SelectScene();
            propertiesPanel.SelectedSprite = null;
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }
        protected void scenePanel_SpriteDeleted(object sender, EventArgs e)
        {
            layersPanel.RemoveSprite((GameSprite)sender);
            propertiesPanel.SelectedSprite = null;
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }
        protected void OnGameElementPanelSpriteBrushSelected(object sender, EventArgs e)
        {
            scenePanel.SpriteBrush = gameElementsPanel.CurrentSelectedSprite;
        }

        protected void layersPanel_SpriteSelected(object sender, EventArgs e)
        {
            //TODO: Re-enabled if using a CTRL+CLICK
            //scenePanel.SelectSprite((GameSprite)sender);
            propertiesPanel.SelectedSprite = (GameSprite)sender;
        }
        protected void layersPanel_SceneSelected(object sender, EventArgs e)
        {
            scenePanel.DeselectSprite();
            layersPanel.SelectScene();
            //propertiesPanel.SelectedSprite = null;
        }
        protected void layersPanel_SpritesZIndexChanged(object sender, EventArgs e)
        {
            scenePanel.ArrangeSpriteZIndex();
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }
        protected void layersPanel_SpriteDeleted(object sender, EventArgs e)
        {
            scenePanel.RemoveSprite((GameSprite)sender);
            propertiesPanel.SelectedSprite = null;
            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }

        protected void scenePanel_MouseMove(object sender, MouseEventArgs e)
        {
            Point p = e.GetPosition(scenePanel.SceneCanvas);
            MousePos.Text = Math.Round(p.X, 2).ToString() + " ; " + Math.Round(p.Y, 2).ToString();
        }
        protected void openLevelDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            level = LevelIO.LoadLevel(openLevelDialog.FileName);

            PrepareLevel();
        }
        protected void levelPropWin_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (levelPropWin.Level == null)
                return;

            level = levelPropWin.Level;

            if (level.IsNew)
                PrepareLevel();

            level.IsNew = false;
        }
        protected void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show("Are you sure you want to quit LevelEditor?", "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (result == MessageBoxResult.No)
                e.Cancel = true;
        }

        protected void navigatorPanel_ZoomValueChanged(object sender, EventArgs e)
        {
            scenePanel.Zoom(navigatorPanel.ZoomValue);

            navigatorPanel.PreviewImage = scenePanel.PreviewImage;
        }

        // Commands Handling
        private LevelProperties levelPropWin;
        public void NewLevelCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            Level newLevel = CreateNewLevel();

            levelPropWin = new LevelProperties();
            levelPropWin.Title = "New Level Properties";
            levelPropWin.Level = newLevel;
            levelPropWin.Owner = this;
            levelPropWin.Closing += new System.ComponentModel.CancelEventHandler(levelPropWin_Closing);
            levelPropWin.Show();
        }

        public void OpenLevelSettingsCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            level.IsNew = false;

            levelPropWin = new LevelProperties();
            levelPropWin.Title = "Level Properties";
            levelPropWin.Level = level;
            levelPropWin.Owner = this;
            levelPropWin.Closing += new System.ComponentModel.CancelEventHandler(levelPropWin_Closing);
            levelPropWin.Show();
        }
        public void OpenLevelSettingsCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }
        private OpenFileDialog openLevelDialog;
        public void OpenLevelCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {

            openLevelDialog = new OpenFileDialog();
            openLevelDialog.AddExtension = true;
            openLevelDialog.DefaultExt = ".xml";
            openLevelDialog.Filter = "Xml documents (.xml)|*.xml";
            openLevelDialog.FileOk += new System.ComponentModel.CancelEventHandler(openLevelDialog_FileOk);

            openLevelDialog.ShowDialog();
        }

        public void OpenLevelCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public void SaveLevelCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            if (level.FilePath != null && level.FilePath != "")
                LevelIO.SaveLevel(level, level.FilePath);
            else
                AppCommands.SaveLevelAsCommand.Execute(null, this);
        }
        public void SaveLevelCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = level != null && level.FilePath != null && level.FilePath != "";
        }

        public void SaveLevelAsCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = level.Name;
            dlg.DefaultExt = ".xml";
            dlg.Filter = "Xml documents (.xml)|*.xml";

            Nullable<bool> result = dlg.ShowDialog();

            if (result == true)
            {
                level.FilePath = dlg.FileName;
                LevelIO.SaveLevel(level, dlg.FileName);
            }
        }
        public void SaveLevelAsCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public void ToggleGridCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public void OpenAboutCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            About about = new About();
            about.Owner = this;
            about.Show();
        }
        public void OpenAboutCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private AssetsManagerWindow assetsManagerWindow;
        public void OpenAssetsManagerCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            assetsManagerWindow = new AssetsManagerWindow();
            assetsManagerWindow.Owner = this;
            assetsManagerWindow.Closing += new System.ComponentModel.CancelEventHandler(assetsManagerWindow_Closing);
            assetsManagerWindow.Show();
        }

        public void OpenAssetsManagerCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private SpriteSheetManagerWindow spriteSheetManagerWindow;
        public void OpenSpriteSheetManagerCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            spriteSheetManagerWindow = new SpriteSheetManagerWindow();
            spriteSheetManagerWindow.Owner = this;
            spriteSheetManagerWindow.Show();
        }
        public void OpenSpriteSheetManagerCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        protected void assetsManagerWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            gameElementsPanel.GameSprites = assetsManagerWindow.Assets.ToList<GameSprite>();
        }

        public void ExitCmd_Executed(object target, ExecutedRoutedEventArgs e)
        {
            this.Close();
        }
        public void ExitCmd_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        public void TogglePhysicEditorCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
            scenePanel.PhysicEditorMode = !scenePanel.PhysicEditorMode;
        }
        public void TogglePhysicEditorCmd_CanExecute(object semder, CanExecuteRoutedEventArgs e) {
            e.CanExecute = layersPanel != null && layersPanel.SelectedLayer != null;
        }
    }
}
